package com.lefevre.cms.web.action.staff;

import com.lefevre.cms.bean.PermissionObject;
import com.lefevre.cms.service.staff.ACLService;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.security.access.ConfigAttribute;
import org.springframework.security.access.SecurityConfig;
import org.springframework.security.web.FilterInvocation;
import org.springframework.security.web.access.intercept.FilterInvocationSecurityMetadataSource;
import org.springframework.security.web.util.matcher.RequestMatcher;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import java.util.*;

/**
 * 资源权限数据源，即定义某一资源可以被哪些角色访问
 *
 * @author Lefevre
 */
@Component
public class CustomFilterInvocationSecurityMetadataSource implements FilterInvocationSecurityMetadataSource, InitializingBean {
    @Resource
    private ACLService aclService;

    private Map<RequestMatcher, Collection<ConfigAttribute>> requestMap = new LinkedHashMap<RequestMatcher, Collection<ConfigAttribute>>();


    @Override
    public Collection<ConfigAttribute> getAllConfigAttributes() {
        Set<ConfigAttribute> allAttributes = new HashSet<ConfigAttribute>();

        for (Map.Entry<RequestMatcher, Collection<ConfigAttribute>> entry : requestMap.entrySet()) {
            allAttributes.addAll(entry.getValue());
        }

        return allAttributes;
    }

    @Override
    public Collection<ConfigAttribute> getAttributes(Object object) throws IllegalArgumentException {
        final HttpServletRequest request = ((FilterInvocation) object).getRequest();
        for (Map.Entry<RequestMatcher, Collection<ConfigAttribute>> entry : requestMap.entrySet()) {

            if (entry.getKey().matches(request)) {
                return entry.getValue();
            }
        }
        return null;
    }

    @Override
    public boolean supports(Class<?> clazz) {
        return FilterInvocation.class.isAssignableFrom(clazz);
    }

    /**
     * 初始化
     */
    @Override
    public void afterPropertiesSet() throws Exception {
        loadResourceDefine();
    }

    private void loadResourceDefine() {
        // 在Web服务器启动时，提取系统中的所有权限。
        //应当是资源为key， 权限为value。 资源通常为url， 权限就是那些以ROLE_为前缀的角色。 一个资源可以由多个权限来访问。
        List<PermissionObject> query = aclService.findModulePermission();

        if (query != null && query.size() > 0) {
            for (PermissionObject permissionObject : query) {
                String methods = null;
                if (permissionObject.getMethods() != null && !"".equals(permissionObject.getMethods())) {
                    methods = permissionObject.getMethods();
                }
                RequestMatcher matcher = new MyAntPathRequestMatcher(permissionObject.getUrl(), methods, true);
                Collection<ConfigAttribute> atts = new ArrayList<ConfigAttribute>();//权限
                ConfigAttribute ca = new SecurityConfig(permissionObject.getPermissionName());
                atts.add(ca);
                if (requestMap.get(matcher) != null) {//处理附加URL情况
                    requestMap.get(matcher).add(ca);
                } else {
                    requestMap.put(matcher, atts);
                }
            }
        }
    }
}
